﻿Imports Microsoft.Xna.Framework.Audio
Imports Microsoft.Xna.Framework
Imports System.Xml

Public Class AudioManager
    Implements IAudioManager

#Region " Fields "
    Private mCurrentMood As String
    Private mTargetMood As String
    Private mMoods As New Dictionary(Of String, AmbientMood)

    Private mTransition As TransitionBase
    Private mTransitioningState As TransitioningState = GameEngine.TransitioningState.Inactive
    Private mTransitionTime As Single = 2 ' Default Transiton Time - In Seconds

    Private mSoundBank As SoundBank
    Private mAudioEngine As AudioEngine
    Private mWaveBank As WaveBank

    Private mMusicVol As Single = 1
    Private mEffectVol As Single = 1

    Private mCurrentMusic As Cue
#End Region

#Region " Properties "
    Public Property AmbientMood() As String Implements IAudioManager.AmbientMood
        Get
            AmbientMood = mCurrentMood
        End Get
        Set(ByVal value As String)
            ' Is the value what is already current?
            If Not mCurrentMood = value AndAlso Not mTargetMood = value Then
                mTargetMood = value
                If mTransitioningState = GameEngine.TransitioningState.Inactive Then
                    PlayMusic()
                Else
                    CueMusic()
                End If
            End If
        End Set
    End Property

    Public Property MusicVol() As Single
        Get
            MusicVol = mMusicVol
        End Get
        Set(ByVal value As Single)
            mMusicVol = MathHelper.Clamp(value, 0, 1)
            mAudioEngine.GetCategory("Music").SetVolume(mMusicVol)
        End Set
    End Property

    Public Property EffectVol() As Single
        Get
            EffectVol = mEffectVol
        End Get
        Set(ByVal value As Single)
            mEffectVol = MathHelper.Clamp(value, 0, 1)
            mAudioEngine.GetCategory("Effects").SetVolume(mMusicVol)
        End Set
    End Property

#End Region

#Region " Initialization "

    Public Overridable Sub Initialise(ByVal Manager As GameManager) Implements IAudioManager.Initialise
    End Sub

    Public Sub LoadContent() Implements IAudioManager.LoadContent
        'TODO

        '' Ideal would be to add a constructor which accepts a config file.
        '' Config file containing location of these files
        'mAudioEngine = New AudioEngine("Content\\Audio\\SoundProject.xgs")
        'mSoundBank = New SoundBank(mAudioEngine, "Content\\Audio\\Sound Bank.xsb")
        'mWaveBank = New WaveBank(mAudioEngine, "Content\\Audio\\Wave Bank.xwb")

        '' Load in all the locations where character cannot walk
        'Dim xml As New XmlDocument
        'Dim am As AmbientMood
        'xml.Load("..\..\..\..\DarkAssassin\Bounds.xml")
        'For Each mood As XmlElement In xml.SelectSingleNode("/game/moods").ChildNodes
        '    am = New AmbientMood(mood.Item("name").InnerText)
        '    For Each track As XmlElement In mood("tracks").ChildNodes
        '        am.Music.Add(track.InnerText)
        '    Next
        '    For Each sound As XmlElement In mood("randomSounds").ChildNodes
        '        am.Sounds.Add(sound.InnerText)
        '    Next
        '    mMoods.Add(am.Name, am)
        'Next
    End Sub

    Public Sub UnloadContent() Implements IAudioManager.UnloadContent
        If mWaveBank IsNot Nothing Then
            mWaveBank.Dispose()
            mWaveBank = Nothing
        End If
        If mSoundBank IsNot Nothing Then
            mSoundBank.Dispose()
            mSoundBank = Nothing
        End If
        If mWaveBank IsNot Nothing Then
            mWaveBank.Dispose()
            mWaveBank = Nothing
        End If
    End Sub

#End Region

    Public Sub PlaySound(ByVal FriendlyName As String) Implements IAudioManager.PlaySound
        mSoundBank.PlayCue(FriendlyName)
    End Sub

    Private Sub PlayMusic()
        mTransition = New TransitionBase(mTransitionTime, AddressOf FadingInComplete)
        mTransitioningState = GameEngine.TransitioningState.TransitioningOn
        mCurrentMusic = mSoundBank.GetCue(mMoods(mTargetMood).RandomTrack)
        mCurrentMusic.Play()
    End Sub

    Private Sub CueMusic()
        mTransition = New TransitionBase(mTransitionTime, AddressOf FadingOutComplete)
        mTransitioningState = GameEngine.TransitioningState.TransitioningOff
    End Sub

    Public Sub Update(ByVal elapsedSeconds As Single) Implements IAudioManager.Update
        ' If we have a transition, we call update on it, then set the volume depending on state; 
        If mTransition IsNot Nothing Then
            mTransition.Update(elapsedSeconds)

            ' if fading out, we set the volume to (1 – fraction complete), 
            If mTransitioningState = TransitioningState.TransitioningOff Then
                mAudioEngine.GetCategory("Music").SetVolume(mTransition.FractionIncomplete)

                ' if fading in, we set the volume to fraction complete.
            ElseIf mTransitioningState = TransitioningState.TransitioningOn Then
                mAudioEngine.GetCategory("Music").SetVolume(mTransition.FractionComplete)
            End If

        End If

        ' TODO
        ' The update routine should launch the randomSounds


        'TODO
        'mAudioEngine.Update()
    End Sub

#Region " Transitions "

    Public ReadOnly Property Transition() As TransitionBase
        Get
            Transition = mTransition
        End Get
    End Property

    Public Property TransitioningState() As TransitioningState
        Get
            TransitioningState = mTransitioningState
        End Get
        Set(ByVal value As TransitioningState)
            mTransitioningState = value
        End Set
    End Property

    Public Property TransitionTime() As Single
        Get
            TransitionTime = mTransitionTime
        End Get
        Set(ByVal value As Single)
            mTransitionTime = value
        End Set
    End Property

    Public Sub FadingOutComplete() Implements IAudioManager.FadingOutComplete
        mAudioEngine.GetCategory("Music").SetVolume(0)

        mTransitioningState = TransitioningState.Inactive
        mTransition = Nothing
        mCurrentMusic.Stop(AudioStopOptions.Immediate)

        ' If the target state is not null, we then immediately start a fading-in transition. 
        If Not mTargetMood = "" Then
            PlayMusic()
        End If
    End Sub

    Public Sub FadingInComplete() Implements IAudioManager.FadingInComplete
        ' Set the volume to 1 and the state to playing.
        mAudioEngine.GetCategory("Music").SetVolume(1)
        mTransitioningState = TransitioningState.Active
        mCurrentMood = mTargetMood
        mTransition = Nothing
    End Sub

#End Region

End Class